using System;
using System.Collections.Generic;
using System.Text;
using DslFactory.Utilities.DteCodeModel;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Modeling;
using System.Net.Security;
using System.ServiceModel;
using System.IO;

namespace Dslfactory.wcfLanguage
{
 internal static class ServiceHostIncrementalCodeGeneration
 {
  /// <summary>
  /// Subscribe to Interface code generation events
  /// </summary>
  /// <param name="Store"></param>
  /// <param name="eventManagerDirectory"></param>
  public static void SubsribeToStoreEvents(Store Store)
  {
   EventManagerDirectory eventManagerDirectory = Store.EventManagerDirectory;

   // When a property of the Interface changes, the [ContractAttribute] must be updated in code
   eventManagerDirectory.ElementPropertyChanged.Add(Store.DomainDataDirectory.GetDomainClass(typeof(Hosting)),
                                                          new EventHandler<ElementPropertyChangedEventArgs>(EnsureHost));
  }


  /// <summary>
  /// Ensure an attribute for interfaces
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="arg"></param>
  private static void EnsureHost(object sender, ElementPropertyChangedEventArgs arg)
  {
   Hosting serviceHost = arg.ModelElement as Hosting;

   // Name
   if (arg.DomainProperty.Id == Service.NameDomainPropertyId)
   {
    // Get the class
    string oldFullName = (string.IsNullOrEmpty(serviceHost.Namespace) ? arg.OldValue as string : serviceHost.Namespace + '.' + arg.OldValue as string);
    KnownCodeTypes knownCodeTypes = KnownCodeTypes.FromStore(serviceHost.Store);
    CodeClass2 codeClass = knownCodeTypes.GetFullNamedType(oldFullName) as CodeClass2;
    CodeElement2 element = codeClass as CodeElement2;
    if (element != null)
    {
     element.RenameSymbol(arg.NewValue as string);
     knownCodeTypes.TakeIntoAccount(element as CodeType, true);
    }
   }
   else
    SynchronizeCodeWithModel(serviceHost);
  }



  /// <summary>
  /// Generateds the service Host
  /// </summary>
  /// <param name="type"></param>
  /// <param name="ns"></param>
  internal static void Generate(TypeOfInterest type, CodeNamespace ns)
  {
   Hosting hosting = type as Hosting;

   // Code
   CodeClass2 codeClass = IncrementalGenerator.EnsureClass(ns, type.Name) as CodeClass2;
   KnownCodeTypes.FromStore(type.Store).TakeIntoAccount(codeClass as CodeType, false);
   SynchronizeCodeWithModel(hosting);

   // App.Config
   string directory = Path.GetDirectoryName(codeClass.ProjectItem.ContainingProject.FileName);
   string appConfigPathname = directory+Path.DirectorySeparatorChar+"App.Config";
   if (hosting.HostedServices.Count > 0)
   {
    Service service = hosting.HostedServices[0];
    if (service.ImplementedServiceContracts.Count > 0)
    {
     ServiceContract contract = service.ImplementedServiceContracts[0];
     if (!File.Exists(appConfigPathname))
     {

      File.WriteAllText(appConfigPathname,
                        CodeGeneration.Code.App_config.Replace("$(Service.Name)", service.Name)
                                                      .Replace("$(Service.FullName)", service.FullName)
                                                      .Replace("$(ServiceContract.FullName)", contract.FullName)
                       );
      codeClass.ProjectItem.ContainingProject.ProjectItems.AddFromFile(appConfigPathname);
     }
    }
   }
  }


  /// <summary>
  /// Generates the code
  /// </summary>
  /// <param name="hosting"></param>
  private static void SynchronizeCodeWithModel(Hosting hosting)
  {
   KnownCodeTypes knownCodeTypes = KnownCodeTypes.FromStore(hosting.Store);
   if (knownCodeTypes == null)
    return;

   // Get the interface
   CodeClass2 codeClass2 = knownCodeTypes.GetFullNamedType(hosting.FullName) as CodeClass2;
   if (codeClass2 != null)
   {
    IncrementalGenerator.EnsureUsings(codeClass2, "System", "System.ServiceModel");
    CodeFunction2 main = IncrementalGenerator.FindMethod(codeClass2, "void Main(string[] args)");
    if (main==null)
     codeClass2.GetStartPoint(vsCMPart.vsCMPartBody).CreateEditPoint().Insert(CodeGeneration.Code.ConsoleHost_Main);


    // Build list of service hosts
    StringBuilder sb = new StringBuilder();
    sb.AppendLine(" new ServiceHost[]");
    sb.AppendLine("  {");
    foreach (Service s in hosting.HostedServices)
    {
     if (s.Namespace!=hosting.Namespace)
      IncrementalGenerator.EnsureUsings(codeClass2, s.Namespace);
     sb.AppendLine("   new ServiceHost(typeof(" + s.Name + ")),");
    }
    sb.AppendLine("  }");

    // And put it as a static field
    CodeVariable field = IncrementalGenerator.EnsureField(codeClass2, "serviceHosts", "ServiceHost[]");
    field.IsShared = true; // static
    field.InitExpression = sb.ToString();
   }
  }
 }
}
